Imports System.Runtime.Serialization

Namespace DataStream

    ''' <summary>
    ''' Holds a log of stream items with a start time
    ''' </summary>
    ''' <remarks></remarks>
    <Serializable(), ObfuscationAttribute(Exclude:=True, ApplyToMembers:=True)> _
    Public Class StreamLog
        Inherits ObjectModel.Collection(Of Stream)
        Implements Runtime.Serialization.ISerializable

        Private mStartTime As Date = Now

        <NonSerialized()> _
        Private mName As String = ""

        <NonSerialized()> _
        Private mRestrictStart As Integer = -1
        <NonSerialized()> _
        Private mRestrictEnd As Integer = -1
        <NonSerialized()> _
        Private mCurrentIndex As Integer = -1
        <NonSerialized()> _
        Private mPlaying As Boolean = True
        Private mValidItems As New ObjectModel.Collection(Of String)

        <NonSerialized()> _
        Private mNewValidItemsCallBack As EventHandler = Nothing
        <NonSerialized()> _
        Private mPlayStateChanged As EventHandler = Nothing
        <NonSerialized()> _
        Private mValidItemsCount As Integer = 0

        Sub New(Optional ByVal name As String = "")
            MyBase.New()
        End Sub

        ''' <summary>
        ''' Specifies a name for the given datalog
        ''' </summary>
        ''' <value></value>
        ''' <returns></returns>
        ''' <remarks></remarks>
        Public Property LogName() As String
            Get
                Return mName
            End Get
            Set(ByVal value As String)
                mName = value
            End Set
        End Property

        ''' <summary>
        ''' Specifies the start for this log. used for naming
        ''' </summary>
        ''' <value></value>
        ''' <returns></returns>
        ''' <remarks></remarks>
        Public Property StartTime() As Date
            Get
                Return mStartTime
            End Get
            Set(ByVal value As Date)
                mStartTime = value
            End Set
        End Property

        ''' <summary>
        ''' Property that holds information about the current selection
        ''' </summary>
        ''' <value></value>
        ''' <returns></returns>
        ''' <remarks></remarks>
        Public Property RestrictStart() As Integer
            Get
                If mRestrictStart = -1 Then
                    Return 0
                Else
                    Return mRestrictStart
                End If
            End Get
            Set(ByVal value As Integer)
                Dim tmp As Integer = mRestrictStart

                If value >= 0 And value < Me.Count Then
                    mRestrictStart = value
                ElseIf value < Me.Count Then
                    mRestrictStart = 0
                Else
                    mRestrictStart = Me.Count - 1
                End If

                If tmp <> mRestrictStart Then
                    StreamStateChangedEvent()
                End If
            End Set
        End Property

        ''' <summary>
        ''' Sets a callback function for handling new Valid Items added
        ''' </summary>
        ''' <value></value>
        ''' <remarks></remarks>
        Public WriteOnly Property NewValidItemsCallback() As EventHandler
            Set(ByVal value As EventHandler)
                mNewValidItemsCallBack = value
            End Set
        End Property

        ''' <summary>
        ''' Causes the new items event handler to be called
        ''' </summary>
        ''' <remarks></remarks>
        Private Sub NewValidItemsEvent()
            If Not IsNothing(mNewValidItemsCallBack) Then
                mNewValidItemsCallBack.Invoke(Me, New System.EventArgs)
            End If
        End Sub

        ''' <summary>
        ''' Sets a callback funciton for handling Play State Changed
        ''' </summary>
        ''' <value></value>
        ''' <remarks></remarks>
        Public WriteOnly Property StreamStateChangedCallback() As EventHandler
            Set(ByVal value As EventHandler)
                mPlayStateChanged = value
            End Set
        End Property

        Private Sub StreamStateChangedEvent()
            If Not IsNothing(mNewValidItemsCallBack) Then
                mPlayStateChanged.Invoke(Me, New System.EventArgs)
            End If
        End Sub

        ''' <summary>
        ''' Property that holds information about the current selection
        ''' </summary>
        ''' <value></value>
        ''' <returns></returns>
        ''' <remarks></remarks>
        Public Property RestrictEnd() As Integer
            Get
                If mRestrictEnd = -1 Then
                    Return Me.Count - 1
                Else
                    Return mRestrictEnd
                End If

            End Get
            Set(ByVal value As Integer)
                Dim tmp As Integer = mRestrictEnd

                If value >= 0 And value < Me.Count Then
                    mRestrictEnd = value
                ElseIf value < Me.Count Then
                    mRestrictEnd = 0
                Else
                    mRestrictEnd = Me.Count - 1
                End If

                If tmp <> mRestrictEnd Then
                    StreamStateChangedEvent()
                End If
            End Set
        End Property
        Public Property CurrentIndex() As Integer
            Get
                If mCurrentIndex = -1 Then
                    Return Me.Count - 1
                Else
                    Return mCurrentIndex
                End If
            End Get
            Set(ByVal value As Integer)
                mCurrentIndex = value
            End Set
        End Property

        Public Property StreamPlaying() As Boolean
            Get
                Return mPlaying
            End Get
            Set(ByVal value As Boolean)
                If value <> mPlaying Then
                    mPlaying = value
                    StreamStateChangedEvent()
                End If
            End Set
        End Property

        Public ReadOnly Property CurrentItem() As Stream
            Get
                If mCurrentIndex = -1 Then
                    If Me.Count > 0 Then
                        Return Me(Me.Count - 1)
                    Else
                        Return Nothing
                    End If
                Else
                    Return Me(mCurrentIndex)
                End If
            End Get
        End Property

        Public ReadOnly Property ValidItems() As ObjectModel.Collection(Of String)
            Get
                If mValidItems Is Nothing Then
                    mValidItems = New ObjectModel.Collection(Of String)
                End If
                If mValidItems.Count = 0 AndAlso Me.Count > 0 Then
                    ValidItemsRefresh()
                End If
                Return mValidItems
            End Get
        End Property

        ''' <summary>
        ''' Refreshes the valid stream items
        ''' </summary>
        ''' <remarks></remarks>
        Public Sub ValidItemsRefresh()
            For Each item As String In DataStream.StreamItem.NameDictionary.Values
                If Not mValidItems.Contains(item) Then
                    mValidItems.Add(item)
                End If
            Next
            NewValidItemsEvent()
        End Sub

        ''' <summary>
        ''' 
        ''' </summary>
        ''' <param name="Info"></param>
        ''' <param name="context"></param>
        ''' <remarks></remarks>
        Protected Sub New(ByVal Info As Runtime.Serialization.SerializationInfo, ByVal context As Runtime.Serialization.StreamingContext)
            MyBase.New()

            Dim version As Integer = 1
            Dim NoCount As Boolean = Info.GetBoolean("NoCount")

            Try
                version = Info.GetInt32("Version")
                ' Me.StartTime = Info.GetValue("StartTime", Me.StartTime.GetType)
            Catch ex As Exception
                version = 1
            End Try

            If Not NoCount Then
                Dim Values As Object = Nothing

                Select Case version
                    Case 1
                        Values = Info.GetValue("Values", GetType(Double()()))
                    Case 2
                        Values = Info.GetValue("Values", GetType(Double()()()))
                End Select

                If Values Is Nothing Then
                    Throw New Exception("Unable to open datalog")
                    Return
                End If

                Dim Indexes()() As Byte = Info.GetValue("Indexes", GetType(Byte()()))
                Dim VarValues()() As Byte = Info.GetValue("VarValues", GetType(Byte()()))
                Dim IndexValues() As String = Info.GetValue("IndexValues", GetType(String()))

                Dim TimeStamps() As DateTime = Info.GetValue("TimeStamps", GetType(DateTime()))
                'Dim ItemIndex() As Integer = Info.GetValue("ItemIndex", GetType(Integer()))

                ' Re-Create the stream
                For i As Integer = 0 To Indexes.Length - 1
                    Dim stream As New DataStream.Stream(TimeStamps(i), i)

                    For x As Integer = 0 To Indexes(i).Length - 1
                        Select Case version
                            Case 1
                                stream.Add(New StreamItem(IndexValues(Indexes(i)(x)), VarValues(i)(x), Values(i)(x)))
                            Case 2
                                stream.Add(New StreamItem(IndexValues(Indexes(i)(x)), VarValues(i)(x), Values(i)(x)))
                        End Select

                    Next
                    Me.Add(stream)
                Next

                Info.GetValue("ValidItems", Me.mValidItems.GetType)


            End If

        End Sub

        Public Sub GetObjectData(ByVal info As System.Runtime.Serialization.SerializationInfo, ByVal context As System.Runtime.Serialization.StreamingContext) Implements System.Runtime.Serialization.ISerializable.GetObjectData
            info.AddValue("StartTime", StartTime, GetType(Date))
            info.AddValue("Version", 2, GetType(Integer))

            If Me.Count > 0 Then
                Dim TimeStamps(Me.Count - 1) As DateTime
                Dim ItemIndex(Me.Count - 1) As Integer
                Dim Indexex(Me.Count - 1)() As Byte
                Dim Values(Me.Count - 1)()() As Double
                Dim VarValues(Me.Count - 1)() As Byte
                Dim Dictionary As New StreamDictionary(0)
                Dim item As StreamItem

                For i As Integer = 0 To Me.Count - 1
                    ReDim Preserve Indexex(i)(Me(i).Count - 1)
                    ReDim Preserve Values(i)(Me(i).Count - 1)
                    ReDim Preserve VarValues(i)(Me(i).Count - 1)
                    Dim cnt As Integer = 0

                    TimeStamps(i) = Me(i).TimeStamp
                    ItemIndex(i) = Me(i).Index
                    For itemCnt As Integer = 0 To Me(i).Count - 1
                        item = Me(i)(itemCnt)
                        If Not IsNothing(item.ValueArray) Then
                            ' ReDim Preserve Values(i)(itemCnt)(CType(item.Value, Double()).Length - 1)
                            Values(i)(cnt) = item.ValueArray
                        Else
                            ReDim Preserve Values(i)(itemCnt)(0)
                            Values(i)(cnt)(0) = item.RawValue
                        End If
                        Indexex(i)(cnt) = Dictionary.Add(item.Name)

                        VarValues(i)(cnt) = item.ItemType
                        cnt += 1
                    Next
                Next
                Dim IndexValues(Dictionary.Count - 1) As String
                For i As Byte = 0 To IndexValues.Length - 1
                    IndexValues(i) = Dictionary(i)
                Next

                info.AddValue("ValidItems", Me.mValidItems, Me.mValidItems.GetType)
                info.AddValue("TimeStamps", TimeStamps, GetType(DateTime()))
                'info.AddValue("ItemIndex", ItemIndex, GetType(Integer()))
                info.AddValue("NoCount", False, GetType(Boolean))
                info.AddValue("Indexes", Indexex, GetType(Byte()()))
                info.AddValue("Values", Values, GetType(Double()()()))
                info.AddValue("VarValues", VarValues, GetType(Byte()()))
                info.AddValue("IndexValues", IndexValues, GetType(String()))
            Else
                info.AddValue("NoCount", True, GetType(Boolean))
            End If

        End Sub

        Protected Overrides Sub InsertItem(ByVal index As Integer, ByVal item As Stream)
            item.Index = index
            MyBase.InsertItem(index, item)

            If item.Count <> mValidItemsCount Or index = 0 Then
                mValidItemsCount = item.Count
                Me.ValidItemsRefresh()
            End If
        End Sub

        Public Overloads Sub Remove(ByVal Start As Integer, ByVal Count As Integer)
            If Me.Count > Start + Count Then
                For i As Integer = 0 To Count - 1
                    Me.RemoveAt(Start)
                Next
            Else
                Throw New ArgumentOutOfRangeException("Count", "Start+Count exceeds collection length")
            End If
        End Sub

    End Class

End Namespace